﻿// Copyright (c) SimpleIdServer. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
using SimpleIdServer.IdServer.Domains.DTOs;
using SimpleIdServer.IdServer.Domains.Extensions;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;

namespace SimpleIdServer.IdServer.Domains
{
    [JsonConverter(typeof(AuthorizationDataConverter))]
    public class AuthorizationData
    {
        /// <summary>
        /// Types of authorization data.
        /// </summary>
        [JsonPropertyName(AuthorizationDataParameters.Type)]
        public string Type { get; set; } = null!;
        /// <summary>
        /// An array of strings representing the location of the resource or resource server.
        /// This is typically composed of URIs.
        /// </summary>
        [JsonPropertyName(AuthorizationDataParameters.Locations)]
        [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public ICollection<string>? Locations { get; set; } = null;
        /// <summary>
        /// An array of strings representing the kinds of actions to be taken at the resource.
        /// The values of the strings are determined by the API being protected.
        /// </summary>
        [JsonPropertyName(AuthorizationDataParameters.Actions)]
        [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public ICollection<string>? Actions { get; set; } = null;
        /// <summary>
        /// An array of strings representing the kinds of data being requested from the resource.
        /// </summary>
        [JsonPropertyName(AuthorizationDataParameters.DataTypes)]
        [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public ICollection<string>? DataTypes { get; set; } = null;
        /// <summary>
        /// A string identifier indicating a specific resource available at the API.
        /// </summary>
        [JsonPropertyName(AuthorizationDataParameters.Identifier)]
        [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public string? Identifier { get; set; } = null;
        [JsonIgnore]
        public Dictionary<string, string> AdditionalData { get; set; } = new Dictionary<string, string>();

        public void AddLocation(string location)
        {
            if (Locations == null) Locations = new List<string>();
            Locations.Add(location);
        }

        public void AddAction(string action)
        {
            if (Actions == null) Actions = new List<string>();
            Actions.Add(action);
        }

        public void AddDataType(string type)
        {
            if (DataTypes == null) DataTypes = new List<string>();
            DataTypes.Add(type);
        }

        public void AddAdditionalData(string key, string value)
        {
            if (AdditionalData == null) AdditionalData = new Dictionary<string, string>();
            if(AdditionalData.ContainsKey(key)) AdditionalData[key] = value;
            else  AdditionalData.Add(key, value);
        }

        public Dictionary<string, object> Serialize()
        {
            var result = new Dictionary<string, object>
            {
                { AuthorizationDataParameters.Type, Type }
            };
            if (Locations != null && Locations.Any())
                result.Add(AuthorizationDataParameters.Locations, Locations);

            if (Actions != null && Actions.Any())
                result.Add(AuthorizationDataParameters.Actions, Actions);

            if (DataTypes != null && DataTypes.Any())
                result.Add(AuthorizationDataParameters.DataTypes, DataTypes);

            if (!string.IsNullOrWhiteSpace(Identifier))
                result.Add(AuthorizationDataParameters.Identifier, Identifier);

            if (AdditionalData != null)
                foreach (var kvp in AdditionalData)
                {
                    try
                    {
                        var node = JsonNode.Parse(kvp.Value);
                        result.Add(kvp.Key, node.SerializeJson());
                    }
                    catch
                    {
                        result.Add(kvp.Key, kvp.Value);
                    }
                }

            return result;
        }
    }
}
